package
{
	import com.greensock.TweenLite;
	
	import flash.display.Bitmap;
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.filters.GlowFilter;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;

	public class GameObject  implements ISelectable, IPersistable
	{
		public var id:int;
		private var hasNextDestination:Boolean = false;
		public var hasNextStore:Boolean;
		public var wantsToShop:Boolean;
		public var shopping:Boolean;
		public var isAtNextStore:Boolean;
		public var isAtDestination:Boolean;
		public var isInMall:Boolean;
		public var m_snUser:SNUser = null;
		private var m_currentState:int;
		private var m_frustrationThreshold:int = 5;
		
		private var m_speed:Number = 1; //squares per second
		
		public var endingPosition:Point;
		public var startingPosition:Point;
		
		public var position:Point;
		public var display:Sprite;
		public var shopper:DisplayObject;
		
		private var nextStore:Store;
		private var storesShopped:Vector.<Store> = new Vector.<Store>;
		private var targetEscalator:Escalator;
		private var m_allOtherShoppers:Vector.<GameObject>;
		
		
		private var m_mall:Mall;
		private var purchasesCounter:int;

		public var deltaAccumulator:int = 0;
		public var m_curTimeCount:int = 0;		
		
		public var finalDestination:Point;
		
		public static const SIZE:int = 32;

		public static const IDLE:int = 3;
		public static const LEFT:int = 1;
		public static const RIGHT:int = 2;
		
		public static const SHOP_TIME:int = 1000;
		public static const WANTS_TO_SHOP_COOLDOWN:int = 10000;
		
		
		
		
		
		public function GameObject(mall:Mall, allOtherShoppers:Vector.<GameObject>, snUser:SNUser = null)
		{
			m_allOtherShoppers = allOtherShoppers;
			m_snUser = snUser;
			shopping = false;
			isInMall = false;
			wantsToShop = true;
			
			
			purchasesCounter = 0;
			
			position = new Point();
			
			display = new Sprite();

			m_mall = mall;

			m_speed = Math.random() + .5;

			shopper = ImageManager.getImage('assets/shopper1_sheet.png');
			shopper.scrollRect = new Rectangle(0,0,0,0);
			shopper.x = -SIZE/2;
			display.addChild(shopper);
			if(snUser != null){
				var profilePic:DisplayObject = ImageManager.getImage(snUser.img);
				profilePic.filters = [new GlowFilter(0,1,4,4,4)];
				profilePic.y = -profilePic.height - 3;
				profilePic.x =  -profilePic.width/2;
				display.addChild(profilePic);
			}
			var blur:int = 0;
			if(m_snUser != null){
				m_speed = 1;
				switch(m_snUser.name){
					case "Brian":
						blur = 15;
						
						break;
					case "Paul":
						blur = 10;
						break;
					default:
						blur = 6;
						break;
				}
				display.filters = [new GlowFilter(0xffff00,.8,blur,blur,4)];
			}		
			
		}

		
		public function step(delta:int):void{
			switch(true){
				case (hasNextDestination):
					moveTowardsNextDestination(delta);
					break;
				case (!isInMall):
					notInMallLogic(delta);
					break;
				case (isAtNextStore):
					shop(delta);
					break;
				case (!wantsToShop):
					goHome();
					break;
				case (!hasNextStore):
					pickNextStore();
					break;
				default:
					pickNextDestination();
					break;

			}
			
			
			updateDisplay();
		}
		
		private var nextDestinationIsEscalator:Boolean = false;
		private var isOnEscalator:Boolean = true;
		
		private function pickNextDestination():void{
			var i:int, l:int;
			var esc:Escalator;
			var closestEsc:Escalator;
			var isAbove:Boolean;
			var verticalDelta:Number;
			
			verticalDelta = nextStore.location.y - this.position.y;
			if(nextDestinationIsEscalator){
				nextDestinationIsEscalator = false;
				isOnEscalator = true;
				if(verticalDelta > 0){
					setDestination(this.position.add(new Point(1,1)));
				} else {
					setDestination(this.position.add(new Point(-1,-1)));
				}
			} else {
				isOnEscalator = false;
				if(verticalDelta != 0){
					if(verticalDelta > 0){
						esc = findEscalatorFloorsAway(0);
						setDestination(esc.location);
					} else {
						esc = findEscalatorFloorsAway(-1);
						setDestination(esc.topLocation);
					}

					if(esc != null){
						nextDestinationIsEscalator = true;
					} else {
						hasNextStore = false;
					}
				} else {
					nextDestinationIsEscalator = false;
					setDestination(nextStore.location);
				}
			}
		}
		
		private function findEscalatorFloorsAway(direction:int):Escalator{
			var i:int, l:int;
			var currentEsc:Escalator;
			var closestEsc:Escalator;
			var currentIsCloser:Boolean = false;
			
			for(i = 0, l = m_mall.escalators.length; i < l; i++){
				currentEsc = m_mall.escalators[i];
				if(currentEsc.location.y == (this.position.y + (direction))){ 
					if(closestEsc){
						if(direction > 0){ 
							// use bottom of escalator as ref point
							currentIsCloser = (currentEsc.location.subtract(this.position).length < closestEsc.location.subtract(this.position).length);
						} else {
							// use top of escalator as ref point
							currentIsCloser = (currentEsc.topLocation.subtract(this.position).length < closestEsc.topLocation.subtract(this.position).length);
						}
						
						if(currentIsCloser){
							closestEsc = currentEsc;
						}
					} else {
						closestEsc = currentEsc;
					}
				}
			}
			
			return closestEsc;
		}
			
		private var m_nextStoreLocation:Point;
		
		private function pickNextStore():void{
			var i:int, l:int;
			var stores:Vector.<Store> = m_mall.stores;
			var openList:Vector.<Store> = new Vector.<Store>;
			var possibleStore:Store;
			nextStore = null;
			for(i = 0, l = stores.length; i < l; i++){
				openList.push(stores[i]);
			}
			
			if(m_mall.stores.length){
				while(openList.length > 0){
					possibleStore = openList[Math.floor(Math.random()*openList.length)];
					
					if(possibleStore.currentStock > 0 && storesShopped.indexOf(possibleStore) == -1){
						nextStore = possibleStore;
						m_nextStoreLocation = nextStore.location.clone();
						storesShopped.push(nextStore);
						hasNextStore = true;
						break;
					} else {
						openList.splice(openList.indexOf(possibleStore), 1);	
					}
				}
			}
			
			if(nextStore == null){
				m_frustrationThreshold--;
				if(m_frustrationThreshold <= 0){
					wantsToShop = false;
				} else {
					var destX:Number = Util.randBetween(m_mall.allowableRectangle.left, m_mall.allowableRectangle.right);
					setDestination(new Point(destX, this.position.y));					
				}
			}
		}
		
		public function setDestination(pnt:Point):void{
			startingPosition = this.position.clone();
			endingPosition = pnt.clone();
			hasNextDestination = true;
		}

		public function forceMallEntry():void{
			m_curTimeCount = WANTS_TO_SHOP_COOLDOWN;
		}
		
		private function notInMallLogic(delta:int):void{
			m_curTimeCount += delta;
			
			if(m_curTimeCount >= WANTS_TO_SHOP_COOLDOWN && m_mall.lettingShoppersIn()){
				m_mall.enterMall(this);
				position = new Point(0,0);
				m_frustrationThreshold = 5;
				m_curTimeCount = 0;
				isInMall = true;
				display.alpha = 0;
				display.visible = true;
				purchasesCounter = 0;
				wantsToShop = true;
				endingPosition = null;
				storesShopped = new Vector.<Store>;
				TweenLite.to(display, 1, {alpha: 1});	
			}
		}
		
		private function shop(delta:int):void{
			m_curTimeCount += delta;
			
			if(m_curTimeCount >= SHOP_TIME){
				m_curTimeCount = 0;

				if(nextStore.currentStock > 0){
					makePurchase(nextStore);	
				}
				nextStore = null;
				hasNextStore = false;
				hasNextDestination = false;
				isAtNextStore = false;
			}
		}
		
		public function goHome():void{
			isInMall = false;
			hasNextDestination = false;
			TweenLite.to(display, 1, {alpha: 0});
		}
		
		public function say(msg:String):void{
			Util.bubbleTextOut(display, m_mall.display, msg, 0xDDDD00, 13);		
			
		}
		
		
		
		private function moveTowardsNextDestination(delta:int):void{
			var row:int ;
			var sequence:Array;
			
			var distanceTraveled:Number = this.position.subtract(this.startingPosition).length;
			var startEndDistance:Number = this.endingPosition.subtract(this.startingPosition).length;
			if(distanceTraveled >= startEndDistance){
				this.position = this.endingPosition.clone();

				if(hasNextStore){
					if(endingPosition.subtract(m_nextStoreLocation).length < .5){
						isAtNextStore = true;
					}
				}
				
				hasNextDestination = false;
			} else {
				var direction:Point = this.endingPosition.subtract(this.position);
				direction.normalize(1);
				
				if(targetEscalator){
					row = (targetEscalator.bottomPoint.x > targetEscalator.topPoint.x) ? RIGHT : LEFT;
					sequence = [0];
				} else {
					row = (direction.x > 0) ? RIGHT : LEFT;
					sequence = [0,1,2,1];
				}
				
				deltaAccumulator += delta;

				var numFrames:int = sequence.length;
				var fps:int = 5;
				var msPerLoop:int = (1000/fps) * numFrames;
				var ms:int = (deltaAccumulator % msPerLoop);
				var imgNum:int = Math.floor(ms / (1000/fps));						
				
				shopper.scrollRect = new Rectangle(sequence[imgNum]*SIZE, SIZE*row, SIZE, SIZE);
				this.position.x += direction.x*(delta / 1000) * m_speed;
				this.position.y += direction.y*(delta / 1000) * m_speed;
			}					
		}
		
		
		private function makePurchase(nextStore:Store):void{
			nextStore.changeStock(-1);
			var amount:int = Math.round(Math.random()*nextStore.value/3 + nextStore.value/12) + Math.floor(nextStore.quality*nextStore.value/20);
			nextStore.owner.cash += amount;
			nextStore.updateXP(1);
			purchasesCounter++;
			Util.bubbleTextOut(display, m_mall.display, "$" + amount, 0x00ff00, 16);
			
			if(Math.pow(purchasesCounter,2) >= m_mall.stores.length){
				wantsToShop = false;
			}
		}
		
		
		private function updateDisplay():void{
			this.display.x = this.position.x * Game.PPS;
			this.display.y = -this.position.y * Game.PPS - SIZE;
		}
		
		
		public function hitTestPoint(point:Point):Boolean{
			return display.hitTestPoint(point.x, point.y);
		}
		public function highlite(val:Boolean):void{
			if(val){
				display.filters = [new GlowFilter(0x00ffff)];
			} else {
				display.filters = [];
			}
		}
		
		public function loadSavedObject(savedObject:Object):void{
			wantsToShop = savedObject['wantsToShop'];
			shopping = savedObject['shopping'];
			isAtNextStore = savedObject['isAtNextStore'];
			isInMall = savedObject['isInMall'];
			if(savedObject['snUser']){
				m_snUser = new SNUser(savedObject['snUser']['name'], savedObject['snUser']['img']);
			}
			
			m_speed = savedObject['speed'];
			m_currentState = savedObject['currentState'];

			position = new Point(savedObject['position']['x'], savedObject['position']['y']);
			
			if(savedObject['nextStoreId']){
				nextStore = m_mall.getStoreById(savedObject['nextStoreId']);
			}
			
			deltaAccumulator = savedObject['deltaAccumulator'];
			m_curTimeCount = savedObject['m_curTimeCount'];			
			
			purchasesCounter = savedObject['purchasesCounter'];
		}
		
		public function getSaveObject():Object{
			var saveObj:Object = new Object();
			saveObj['id'] = id;
			saveObj['wantsToShop'] = wantsToShop;
			saveObj['shopping'] = shopping;
			saveObj['isAtNextStore'] = isAtNextStore;
			saveObj['isInMall'] = isInMall;
			
			if(m_snUser){
				saveObj['snUser'] = new Object();
				saveObj['snUser']['img'] = m_snUser.img;
				saveObj['snUser']['name'] = m_snUser.name;
			}

			saveObj['currentState'] = m_currentState;			
			
			saveObj['speed'] = m_speed;

			if(startingPosition){
				saveObj['startingPosition'] = new Object();
				saveObj['startingPosition']['x'] = startingPosition.x;
				saveObj['startingPosition']['y'] = startingPosition.y;
			}
			
			if(endingPosition){
				saveObj['endingPosition'] = new Object();
				saveObj['endingPosition']['x'] = startingPosition.x;
				saveObj['endingPosition']['y'] = startingPosition.y;
			}			
			
			saveObj['position'] = new Object();
			saveObj['position']['x'] = position.x;
			saveObj['position']['y'] = position.y;						

			
			if(nextStore){
				saveObj['nextStoreId'] = nextStore.id;
			}
			saveObj['purchasesCounter'] = purchasesCounter;
			saveObj['deltaAccumulator'] = deltaAccumulator;
			saveObj['m_curTimeCount'] = m_curTimeCount;

			return saveObj;
		}
	}
}